package edu.gatech.cs2340.mule.model;
import java.io.Serializable;
import java.util.Random;

/**
 * 
 * Keeps track of data related to the Game itself
 * 
 * @author Zach Elliott
 *
 */
public class MuleGame implements Serializable {
	
	private static final long serialVersionUID = -4639473162033141333L;
	
	private static final int BEGINNER_FOOD_AMOUNT = 8;
	private static final int BEGINNER_ENERGY_AMOUNT = 4;
	private static final int STANDARD_FOOD_AMOUNT = 4;
	private static final int STANDARD_ENERGY_AMOUNT = 2;
	
	private int currentRound;
	private Random randomNumGenerator;	
	private Player[] players;
	private Map map;
	private String difficulty;
	private TurnEngine turnEngine;
	private boolean placingMule;
	private boolean inLandSelectionPhase;
	private boolean buyingLand;
	private boolean inLandGrantPhase;
	private Mule unplacedMule;
	
	/**
	 * Constructs a new game with the given players, map type, and difficulty
	 * 
	 * @param allPlayers all the players that will take part in the game
	 * @param mapType the map type that will be played on
	 * @param gameDifficulty the difficulty that will be played
	 */
	public MuleGame(Player[] allPlayers, String mapType, String gameDifficulty) {
		players = allPlayers;
		currentRound = 1;
		randomNumGenerator = new Random();
		turnEngine = new TurnEngine(players);
		placingMule = false;
		buyingLand = false;
		inLandSelectionPhase = true;
		inLandGrantPhase = true;
		
		if(mapType.equals("Classic")) {
			map = new Map();
		}
		else {
			map = new Map(mapType);
		}
		difficulty = gameDifficulty;
		if(difficulty.equals("Beginner")) {
			for(int i = 0; i < players.length; i++) {
				players[i].setFoodAmount(BEGINNER_FOOD_AMOUNT);
				players[i].setEnergyAmount(BEGINNER_ENERGY_AMOUNT);
			}	
		}
		else {
			for(int i = 0; i < players.length; i++) {
				players[i].setFoodAmount(STANDARD_FOOD_AMOUNT);
				players[i].setEnergyAmount(STANDARD_ENERGY_AMOUNT);
			}	
		}
		
			
	}
	
	/**
	 * 
	 * @return The players in the game
	 */
	public Player[] getPlayers() {
		return players;
	}
	
	/**
	 * 
	 * @return The map of the game
	 */
	public Map getMap() {
		return map;
	}
	
	/**
	 * 
	 * @return The difficulty of the game
	 */
	public String getDifficulty() {
		return difficulty;
	}
	
	/**
	 * 
	 * @return The Random object to be used throughout the game
	 */
	public Random getRandomNumGenerator() {
		return randomNumGenerator;
	}
	
	/**
	 * 
	 * @return The current round of the game
	 */
	public int getRoundNumber() {
		return currentRound;
	}
	
	/**
	 * 
	 * @return The TurnEngine to be used in the game
	 */
	public TurnEngine getTurnEngine() {
		return turnEngine;
	}
	
	/**
	 * 
	 * @return True if a player is placing a mule, false otherwise
	 */
	public boolean isPlacingMule() {
		return placingMule;
	}
	
	/**
	 * 
	 * @param b True if the player is placing a mule, if not false
	 */
	public void setIsPlacingMule(boolean b) {
		placingMule = b;
	}
	
	/**
	 * 
	 * @return True if the player is buying land, false otherwise
	 */
	public boolean isBuyingLand() {
		return buyingLand;
	}
	
	/**
	 * 
	 * @param b True if the player is buying land, if not false
	 */
	public void setIsBuyingLand(boolean b) {
		buyingLand = b;
	}
	
	/**
	 * 
	 * @return True if the land grant phase is occurring, false otherwise
	 */
	public boolean isInLandGrantPhase() {
		return turnEngine.getGameRound() <= 2;
	}
	
	/**
	 * 
	 * @return True if the land grant phase is occurring, false otherwise
	 */
	public void setInLandGrantPhase(boolean b) {
		inLandGrantPhase = b;
	}
	
	/**
	 * 
	 * @return True if the land selection phase is occurring, false otherwise
	 */
	public boolean checkInLandSelectionPhase() {
		if(turnEngine.getNumPassesPerRound() >= players.length) {
			inLandSelectionPhase = false;
		}
		
		return inLandSelectionPhase;
	}
	
	/**
	 * 
	 * @return The Land office interface object to be used in the game
	 */
	public LandOfficeInterface createLandOfficeInterface() {
		return new LandOfficeInterface(this, getMap().getTown().getLandOffice());
	}
	
	/**
	 * 
	 * @return The pub interface object to be used in the game
	 */
	public PubInterface createPubInterface() {
		return new PubInterface(this, getMap().getTown().getPub(), turnEngine);
	}
	
	/**
	 * 
	 * @return The store interface object to be used in the game
	 */
	public StoreInterface createStoreInterface() {
		return new StoreInterface(getMap().getTown().getStore());
	}
	
	/**
	 * 
	 * @param mule The mule to be placed on a tile
	 */
	public void setUnplacedMule(Mule mule) {
		unplacedMule = mule;
	}
	
	/**
	 * 
	 * @return The mule being placed on a tile
	 */
	public Mule getUnplacedMule() {
		return unplacedMule;
	}
}
